<?php
namespace cfd\doc\components;

use yii\base\UserException;
use yii\db\ActiveRecord;
use yii\helpers\ArrayHelper;

class DocObject{
    private $objects=[];
    private $relectionMap=[];
    private $modelsMap=[];
    public function __construct($objects)
    {
        $this->objects = $objects;
        $this->modelsMap = \Yii::$app->getModule('doc')->modelsMap;
    }

    public function getObjectNew($str)
    {
        $ret = [];
        //@List{@User-mixed-用户信息{username-string-用户名,mobile},name-string-姓名,age-int-年龄,@Activity{*,@ActivityData{*},Activity{*}}}
        $str_arr = $this->parts($str);
        foreach($str_arr as $str){
            if(preg_match('/(.*?)(?:\{)(.*)(?:\})/i', $str, $match) && isset($match[1]) && isset($match[2])){
                $obj_name = strpos($match[1],'@')!==false ? substr($match[1],1) : $match[1];
                $obj_name_arr = explode('-',$obj_name);

                $class_list = $this->findClassName($obj_name_arr[0]);
                $classComment = '';
                $labels = [];
                if(!empty($class_list)){
                    foreach($class_list as $classname){
                        /** @var ActiveRecord $model */
                        $model = new $classname;
                        $classComment .= (new \ReflectionClass($model))->getDocComment();
                        $labels = ArrayHelper::merge($model->attributeLabels(),$labels);
                    }
                    $str2_arr  = $this->parts($match[2]);
                    foreach($str2_arr as $str2){
                        if(preg_match('/(.*?)(\{.*\})/i', $str2, $result) && isset($result[1]) && isset($result[2])){
                            $obj_name2 = strpos($result[1],'@')!==false ? substr($result[1],1) : $result[1];
                            $docoment_arr = explode('-',$obj_name2);
                            if(isset($docoment_arr[1]) && isset($docoment_arr[2])){
                                $ret[] = [
                                    $docoment_arr[1],
                                    $str2,
                                    $docoment_arr[2]
                                ];
                            }else{
                                $ret[] = [
                                    'mixed',
                                    $str2,
                                    '/'
                                ];
                            }
                        }else{
                            $docoment_arr = explode('-',$str2);
                            if(isset($docoment_arr[1]) && isset($docoment_arr[2])){
                                $ret[] = [
                                    isset($docoment_arr[1]) && $docoment_arr[1] ? $docoment_arr[1] : '/',
                                    isset($docoment_arr[0]) && $docoment_arr[0] ? $docoment_arr[0] : '/',
                                    isset($docoment_arr[2]) && $docoment_arr[2] ? $docoment_arr[2] : '/',
                                ];
                            }else{
                                if (is_subclass_of($model, 'yii\db\ActiveRecord')) {
                                    if(preg_match("/(\*)[\[]?([\w\|]*)[\]]?/i",$docoment_arr[0],$pattern)){ //*取全部属性 *[title] []中代表排除
                                        if($pattern[1]=="*"){
                                            $remove_arr = explode('|',$pattern[2]);
                                            $attributes = array_keys($labels);
                                            foreach($attributes as $key => $attribute){
                                                if(in_array($attribute,$remove_arr)){
                                                    unset($attributes[$key]);
                                                }
                                            }
                                        }

                                    }else{
                                        $attributes = [$docoment_arr[0]];
                                    }
                                    foreach($attributes as $attr){
                                        $a = $attr;

                                        preg_match_all("/property (.*)/i",$classComment,$ms);
                                        $matches =[];
                                        foreach($ms[0] as $m){
                                            $arr = explode(' ',$m);
                                            $arr = array_map('trim',$arr);
                                            $arr[2] = substr($arr[2],1);
                                            $matches[$arr[2]] = $arr;
                                        }
                                        $type = isset($matches[$a][1]) ? $matches[$a][1] : '';
                                        if(isset($matches[$a][3])){
                                            $label = $matches[$a][3];
                                        }elseif(isset($labels[$a])){
                                            $label = $labels[$a];
                                        }else{
                                            $label = '';
                                        }
                                        $ret[] = [
                                            $type,
                                            $a,
                                            $label
                                        ];
                                    }
                                }else{
                                    throw new UserException("{$classname} 不存在");
                                }
                            }
                        }
                    }
                }else{
                    //普通标识，非类标识
                    $str2_arr  = $this->parts($match[2]);
                    foreach($str2_arr as $str2){
                        if(preg_match('/(.*?)(\{.*\})/i', $str2, $result) && isset($result[1]) && isset($result[2])){
                            $obj_name2 = strpos($match[1],'@')!==false ? substr($result[1],1) : $result[1];
                            $docoment_arr = explode('-',$obj_name2);

                            if(isset($docoment_arr[1]) && isset($docoment_arr[2])){
                                $ret[] = [
                                    $docoment_arr[1],
                                    $str2,
                                    $docoment_arr[2]
                                ];
                            }else{
                                $ret[] = [
                                    'mixed',
                                    $str2,
                                    '/'
                                ];
                            }
                        }else{
                            $docoment_arr = explode('-',$str2);
                            $ret[] = [
                                isset($docoment_arr[1]) && $docoment_arr[1] ? $docoment_arr[1] : '/',
                                isset($docoment_arr[0]) && $docoment_arr[0] ? $docoment_arr[0] : '/',
                                isset($docoment_arr[2]) && $docoment_arr[2] ? $docoment_arr[2] : '/',
                            ];
                        }
                    }
                }
            }
        }
        return $ret;
    }

    /**
     * @param $name
     * @return array
     */
    public function findClassName($name){
        $class_list = [];
        if(strpos($name,"\\")===0){
            //完整全名空间
            return [$name];
        }else {
            foreach ($this->modelsMap as $namespace){
//                $class = $namespace . ucfirst($name);
                $class = $namespace . $name;
                //找到类就返回，没有返回最后一个
                if (class_exists($class)) {
                    $class_list[] = $class;
                }
            }
            return $class_list;
        }
    }

    /**
     * 获取字符在一个字符串中第n次出现的位置
     * @param $str
     * @param $find
     * @param $n
     * @return false|int|mixed
     */
    public function str_n_pos($str,$find,$n){
        $pos_val=0;
        for ($i=1;$i<=$n;$i++){
            $pos = strpos($str,$find);
            if($i!=1){
                $str_left = substr($str,0,$pos);
                $times = substr_count($str_left,'{');
                $n = $n + $times;
            }
            $str = substr($str,$pos+1);
            $pos_val=$pos+$pos_val+1;
        }
        return $pos_val-1;
    }

    /**
     * 拆分字符串
     * @param $str
     * @return array|false|string[]
     */
    public function parts($str)
    {
        $pos = strpos($str,'}');
        if($pos!==false){
            $times = substr_count($str,'{',0,$pos);
            $end_pos = $this->str_n_pos($str,'}',$times);
            $part = substr($str,0,$end_pos+1);
            $part_other = substr($str,$end_pos+2);
        }else{
            $part = $str;
            return explode(',',$part);
        }
        if(preg_match('/(@?[A-Z].*?)(\{.*\})/', $part, $match)){

            $part2 = str_replace($match[2],'',$part);
            $arr = explode(',',$part2);

            foreach($arr as  &$item){
                if($item == $match[1]){
                    $item = $item . $match[2];
                }
            }
            if(!$part_other){
                return $arr;
            }
        }else{
            $arr = explode(',',$part);
        }

        $arr2 = $this->parts($part_other);
        return array_merge($arr,$arr2);

        return $arr;
    }
}